package com.shiliuzi.www.service.impl;

import com.shiliuzi.www.common.Code;
import com.shiliuzi.www.common.Result;
import com.shiliuzi.www.exception.GlobalException;
import com.shiliuzi.www.mapper.MemberMapper;
import com.shiliuzi.www.pojo.bo.PowerBo;
import com.shiliuzi.www.pojo.bo.UserInfoBo;
import com.shiliuzi.www.pojo.dto.user.UserLoginCheckDto;
import com.shiliuzi.www.pojo.dto.user.UserLoginMQDto;
import com.shiliuzi.www.pojo.dto.user.UserLoginSendDto;
import com.shiliuzi.www.pojo.dto.user.UserSetRoleDto;
import com.shiliuzi.www.pojo.po.User;
import com.shiliuzi.www.pojo.vo.user.UserLoginCheckVo;
import com.shiliuzi.www.pojo.vo.user.UserLoginSendVo;
import com.shiliuzi.www.pojo.vo.user.UserLoginShowVo;
import com.shiliuzi.www.pojo.vo.user.UserSetRoleVo;
import com.shiliuzi.www.service.LoginService;
import com.shiliuzi.www.util.CommonUtil;
import com.shiliuzi.www.util.EmailUtil;
import com.shiliuzi.www.util.RedisUtil;
import com.shiliuzi.www.util.mqUtil.MQWrite;
import com.shiliuzi.www.util.userUtil.JWTUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Date;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

import static com.shiliuzi.www.common.Prefix.LOGIN_USER_SEND;
import static com.shiliuzi.www.common.Prefix.LOGIN_USER_TOKEN;

@Slf4j
@Service
public class LoginServiceImpl implements LoginService {

    @Resource
    private MQWrite mqWrite;

    @Resource
    private CommonUtil commonUtil;

    @Resource
    private MemberMapper memberMapper;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private JWTUtil jwtUtil;

    @Override
    @Transactional
    //TODO 使用消息队列，异步发送
    public Result loginSendEmail(UserLoginSendDto userLoginSendDto) {

        if (memberMapper.userIsExist(userLoginSendDto) == null)
            return Result.error(Code.ERROR,"该用户不存在！请重新输入学号和邮箱！");

        //将学号和UUID组装作为key放在redis
        Integer code = commonUtil.randomCode();
        String redisKey = LOGIN_USER_SEND + UUID.randomUUID().toString() + userLoginSendDto.getNumber();

        commonUtil.obtainThread(()->{
            log.info("正在发送邮箱到{}",userLoginSendDto.getEmail());
            mqWrite.sendEmailMessage(new UserLoginMQDto(userLoginSendDto.getEmail(), "验证码", code));
        });

        redisUtil.setRedis(redisKey,code,60l,TimeUnit.SECONDS);

        return Result.success(Code.SUCCESS,
                new UserLoginSendVo(
                        userLoginSendDto.getNumber(),
                        userLoginSendDto.getEmail(),
                        redisKey));
    }

    @Override
    //TODO 同一用户禁止多台登录
    public Result loginCheck(UserLoginCheckDto userLoginCheckDto) {
        try {
            UserLoginSendVo userLoginSendVo = userLoginCheckDto.getUserLoginSendVo();
            String code = (String) redisUtil.getRedis(userLoginSendVo.getRedisKey(),String.class);

            if (code==null) return Result.error(Code.ERROR,"验证码已过期！");

            if (!code.equals(userLoginCheckDto.getCode().toString())) return Result.error(Code.ERROR,"验证码错误！请重新输入！");

            //发放令牌
            //从数据库中获取用户信息
            User userInfo = memberMapper.getUserInfo(userLoginSendVo.getNumber(), userLoginSendVo.getEmail());

            //对象封装转换，将po转化成bo
            UserInfoBo userInfoBo = commonUtil.copyProperties(userInfo,UserInfoBo.class);

            //存入redis，存入token
            Date nowDate = new Date();
            String token = jwtUtil.createToken(userInfoBo,nowDate,commonUtil.expireDate(nowDate,60*10l));

            if(!redisUtil.setRedis(LOGIN_USER_TOKEN + token,token,10l,TimeUnit.MINUTES))
                return Result.error(Code.SYS_ERR,"系统内部出错！redis宕机！");

            if(!PowerBo.obtainPower(userInfoBo.getId(), memberMapper.getUserPower(userInfoBo)))
                return Result.error(Code.SYS_ERR,"系统内部出错！数据库宕机！");

            return Result.success(Code.SUCCESS,new UserLoginCheckVo(token,
                    commonUtil.copyProperties(userInfoBo, UserLoginShowVo.class)));
        } catch (Exception e) {
            throw new GlobalException(Code.SYS_ERR, "系统内部出错！请稍后重试！");
        }
    }

    @Override
    public Result loginOutOfTable() {
        log.info("客户端退出登录！");
        if(PowerBo.clearPower()) return Result.success(Code.SUCCESS,"登出成功！");
        else return Result.error(Code.ERROR,"未登录，无法登出！");
    }
}
